package event

import (
	"fmt"
	"github.com/TarsCloud/TarsGo/tars"
	"sync"
)

type EventIF interface {
	Init() interface{}
	ClearObserver()
	CountObserver() int
	IsContainObserver(handler interface{}) bool
	AddObserver(handler interface{}) bool
	RemoveObserver(handler interface{}) bool
	SyncNotify(params ...interface{}) bool
	AsyncNotify(params ...interface{})
}

// 通知简易事件类（观察者模式）
// 	备注：
// 		第一：简易之处在于 AddObserver 传入的是仅仅是监听模块的处理事件函数；
//		第二：在使用过程中可忽略监听者的封装、事件封装，直接使用模块函数作为监听者；
type EasyEvent struct {
	EventIF
	lock       sync.Mutex
	canBreak	bool	// 不同监听者处理有错误是否影响其他监听者的执行，true：是；false：否
	evtHandler map[string][]interface{}
}

// 创建同步事件对象
//	参数说明：
// 		canBreak:不同监听者处理有错误是否影响其他监听者的执行，true：是；false：否
//		如果外部业务逻辑依赖所有监听者都正确执行，就需要填true，否则填false
func NewEasyEvent(canBreak bool) *EasyEvent {
	return new(EasyEvent).Init(canBreak).(*EasyEvent)
}

// 事件对象初始化
func (this *EasyEvent) Init(canBreak bool) interface{} {
	this.evtHandler = map[string][]interface{}{}
	return this
}

// 清空监听者
func (this *EasyEvent) ClearObserver() {
	this.evtHandler = map[string][]interface{}{}
}

// 监听者数量
func (this *EasyEvent) CountObserver() int {
	return len(this.evtHandler)
}

// 监听者是否存在
func (this *EasyEvent) IsContainObserver(handler interface{}) bool {
	handlerAddr := fmt.Sprintf("%p", handler)
	if _, ok := this.evtHandler[handlerAddr]; ok {
		return true
	}
	return false
}

// 获取监听信息
func (this *EasyEvent) GetObserverInfo(handler interface{}) []interface{} {
	handlerAddr := fmt.Sprintf("%p", handler)
	observer, ok := this.evtHandler[handlerAddr]
	if ok {
		return observer
	}
	return nil
}

// 添加监听者
//	handler interface{} 	监听处理函数
// 	funcName string			监听处理函数名字（仅用于日志记录）
func (this *EasyEvent) AddObserver(handler interface{}, funcName string) bool {
	this.lock.Lock()
	defer this.lock.Unlock()
	if this.IsContainObserver(handler) {
		tars.TLOG.Errorf("增加监听[%p|%s]失败", handler, funcName)
		return false // 返回false仅表示handler已存在，并非错误
	}
	handlerAddr := fmt.Sprintf("%p", handler)
	this.evtHandler[handlerAddr] = []interface{}{handler, funcName}
	tars.TLOG.Infof("增加监听[%p|%s]成功", handler, funcName)
	return true
}

// 移除监听者
func (this *EasyEvent) RemoveObserver(handler interface{}, funcName string) bool {
	this.lock.Lock()
	defer this.lock.Unlock()
	if !this.IsContainObserver(handler) {
		tars.TLOG.Errorf("移除监听[%p|%s]失败", handler, funcName)
		return false
	}
	handlerAddr := fmt.Sprintf("%p", handler)
	delete(this.evtHandler, handlerAddr)
	tars.TLOG.Infof("移除监听[%p|%s]成功", handler, funcName)
	return true
}

// 同步通知所有监听者处理
//	备注：
// 		其中有一个监听者返回false，这里的结果就返回false
//		全部监听者执行返回true，这里的结果才会返回true
func (this *EasyEvent) SyncNotify(params ...interface{}) bool {
	return this.notifyObserver(params ...)
}

// 异步通知所有监听者处理
func (this *EasyEvent) AsyncNotify(params ...interface{}) {
	go this.notifyObserver(params ...)
}

func (this *EasyEvent) notifyObserver(params ...interface{}) bool {
	result := true
	for _, observer := range this.evtHandler {
		handler := observer[0]
		funcName := observer[1].(string)
		ret := handler.(func(...interface{}) bool)(params...)
		if !ret { // 某个handler处理出问题，则终止循环，说明该次没完成通知所有监听者
			result = false
			tars.TLOG.Errorf("通知监听[%p:%s]失败", handler, funcName)
			if this.canBreak {
				tars.TLOG.Errorf("通知监听[%p:%s]失败, 终止执行其他监听", handler, funcName)
				break
			}
		}
	}
	return result
}

